Skip to content

布隆过滤器(Bloom Filter)结构

核心特性

空间高效的概率型数据结构,用于判断 “元素是否存在”

特点:有假阳性(可能误判不存在的元素为存在),无假阴性(存在的元素一定能判断存在)

核心概念:位数组(存储二进制位)、多个哈希函数(将元素映射到位数组的多个索引)

代码实现(小顶堆)

js
class BloomFilter {
  constructor(size = 1024, hashCount = 3) {
    this.size = size; // 位数组大小(越大,假阳性率越低)
    this.hashCount = hashCount; // 哈希函数数量(越多,假阳性率越低,但插入/查询开销越大)
    this.bitArray = new Uint8Array(size).fill(0); // 位数组(用Uint8Array节省空间,每个元素存储8个二进制位)
  }

  // 哈希函数(简单版:基于不同种子计算哈希值)
  _hash(value, seed) {
    const strValue = String(value);
    let hash = 0;
    for (let i = 0; i < strValue.length; i++) {
      hash = (hash * seed + strValue.charCodeAt(i)) % this.size;
    }
    return hash;
  }

  // 添加元素
  add(value) {
    for (let i = 0; i < this.hashCount; i++) {
      const index = this._hash(value, i + 1); // 不同种子生成不同哈希值
      const byteIndex = Math.floor(index / 8); // 计算所在字节的索引
      const bitIndex = index % 8; // 计算字节内的位索引
      this.bitArray[byteIndex] |= 1 << bitIndex; // 将对应位设为1
    }
  }

  // 判断元素是否存在(可能有假阳性)
  has(value) {
    for (let i = 0; i < this.hashCount; i++) {
      const index = this._hash(value, i + 1);
      const byteIndex = Math.floor(index / 8);
      const bitIndex = index % 8;
      // 检查对应位是否为1,若有一个为0,则元素一定不存在
      if ((this.bitArray[byteIndex] & (1 << bitIndex)) === 0) {
        return false;
      }
    }
    return true; // 所有位都为1,元素可能存在(假阳性)
  }
}

适用场景

缓存穿透防护:如 Redis 缓存中,用布隆过滤器存储已存在的 key,查询时先通过布隆过滤器判断,不存在则直接返回,避免穿透到数据库

重复请求拦截:如用户频繁点击按钮发送请求,用布隆过滤器存储已发送的请求 ID,避免重复发送

大规模数据去重:如处理亿级用户 ID,用布隆过滤器快速判断 ID 是否已存在(无需存储完整 ID,节省空间)

注意

位数组大小和哈希函数数量需根据数据量调整(可通过公式计算最优值)

不适合需要 “精确判断存在” 的场景(如用户登录验证),适合 “允许少量误判” 的场景